#include <iostream>
using namespace std;
#include <string>
#include <cerrno>
#include<cstdio>
// 这四个头文件是写套接字经常用到的
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

void Usage(char *proc)
{
    cout << "Usage: " << proc << " port " << endl;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
    }
    const uint16_t port = atoi(argv[1]);
    // 1.创建套接字,返回值是文件描述符
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) // 创建失败
    {
        cerr << "socket create error:" << errno << endl;
        return 1;
    }
    // 2.给该服务器绑定端口和ip（ip需要特殊处理）
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(port); // 此处的端口号是计算机上的变量，属于主机序列，要主机转网络序列htons()
    // a.需要将人识别的点分十进制字符串风格转化为四字节整数IP
    // b.需要考虑大小端
    // 直接使用接口  in_addr_t inet_addr(const char* cp);能完成上面ab两个工作
    // 但是云服务器不允许用户直接bind 公网IP，并且实际上我们也不会指明IP,更关心port
    // INADDR_ANY:
    // 如果bind的是确定的IP（主机），意味着只有发到该主机上的数据才会交给你的网络进程
    // 但是一般服务器可能有多张网卡，配置多个IP，我们需要的不是某个IP上的数据，我们需要的是所有发送到该主机端口的数据
    // local.sin_addr.s_addr = inet_addr("49.235.126.74");//ip地址,点分十进制，字符串风格 [0-255],[0-255],[0-255],[0-255]
    local.sin_addr.s_addr = INADDR_ANY;
    // 传参时需要对local强转为通用结构体类型
    if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0)
    {
        cerr << "bind error :" << errno << endl;
        return 2;
    }
    // 3.提供服务
    bool quit = false;
#define NUM 1024
    while (!quit)
    {
        char buffer[NUM] = {0};
        struct sockaddr_in client;
        socklen_t len = sizeof(client); // len指明客户端信息结构体大小
        // 对udp需要用专门的接口读取数据
        recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&client, &len); // flag 设为 0
        cout << "client :> " << buffer << endl;
        // 给客户端返回信息
        string ret_info = "This is server";
        sendto(sock, ret_info.c_str(), ret_info.size(), 0, (struct sockaddr *)&client, len);
    }

    return 0;
}